Java Blog

Since I'm very lazy in sharing my thoughts, this blog may contain very few posts - so please be patient! :-)

Dienstag, April 15, 2008

Wie bestimme ich das JAR einer Java-Klasse?

Vor kurzem hatte ich die Notwendigkeit, zur Laufzeit den Pfad zum JAR einer geladenen Java-Klasse zu erfahren und musste erfahren, dass es in Java hier erstaunlicherweise keinen Standardweg gibt. Na gut - Java ist bnun nicht die dynamischste Sprache, aber eine solche Funktionalität hätte ich schon erwartet - schließlich muss die JVM buzw. der ClassLoader ja auch wissen, woher er physisch seine Klassen holt bzw. geholt hat.

Als erstes bin ich auf die "ProtectionDomain - CodeSource"-Strategie gestoßen - in einem Artikel von Roedy Green's "Java Glossary" mit einem Code-Beispiel hinterlegt.

Für die meisten Fälle scheint das auch zu funktionieren, obwohl es nun überhaupt nichts mit dem der Klasse zugrunde liegenden JAR zu tun hat, sondern offenbar eher ein Standardverhalten der JVM ausnutzt.

Unglücklicherweise funktioniert das beschriebene Verfahren auch nicht immer. Problematisch wird es nämlich genau dann, wenn eine Bibliothek "Schweinereien" mit dem ClassLoader bzw. dem Security-Mechanismus von Java macht.
Maven 1.1 scheint so ein Fall zu sein. Beim Laufenlassen der JUnit-Tests eines Maven-1.1-Projekts nämlich zeigten alle CodeSource-Referenzen immer auf das erste JAR im MAVEN_HOME/lib-Verzeichnis: ant-1.6.5.jar.

Nach weiterer intensiver Forschung stieß ein Kollege von mir auf eine weitere - eigentlich viel näher liegende - Lösung für das Problem "JAR zu einer Klasse".
Im Blog von Nirav Thaker steht eine Lösung beschrieben, die mit Standard-Java-Mitteln arbeitet und eine JarURLConnection benutzt, um den Pfad zu dem JAR einer Klasse bestimmt. Für die Eiligen hier schnell der Quellcode:

public static URL getJarURL(Class clazz) {
String classResource = "/" + clazz.getPackage().getName().replace('.', '/')
+ "/" + clazz.getSimpleName() + ".class";
URL clsUrl = clazz.getResource(classResource);
if (clsUrl != null) {
try {
URLConnection conn = clsUrl.openConnection();
if (conn instanceof JarURLConnection) {
JarURLConnection connection = (JarURLConnection) conn;
return connection.getJarFileURL();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}

Im Gegensatz zu der bei Nirav veröffentlichten Version funktioniert diese Methode hier auch bei Klassen, die nicht im Default-Package liegen :o)...

Labels: ,